package org.ziwei.rule.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.reflections.Reflections;
import org.ziwei.paipan.Gong;
import org.ziwei.paipan.MingPan;
import org.ziwei.paipan.Star;
import org.ziwei.paipan.var.DiZhi;
import org.ziwei.paipan.var.StarCode;

public class RuleUtils {

	public static <T> Set<Class<? extends T>> findClassByInterface(String packagePath, Class<T> clazz){
		Reflections reflections = new Reflections(packagePath);    
		Set<Class<? extends T>> classes = reflections.getSubTypesOf(clazz);
		return classes;
	}
	
	public static <T> List<T> getInstanceByInterface(String packagePath, Class<T> clazz) throws InstantiationException, IllegalAccessException{
		Set<Class<? extends T>> classes = findClassByInterface(packagePath, clazz);
		List<T> instances = new ArrayList<T>();
		for(Class<? extends T> c : classes){
			T t = c.newInstance();
			instances.add(t);
		}
		return instances;
	}
	
	public static Gong mingGong(MingPan pan){
		DiZhi diZhi = pan.getMingGong();
		return pan.getGongList().get(diZhi.ordinal());
	}
	
	/**
	 * @param pan
	 * @return
	 */
	public static List<Star> mingGongZhengYao(MingPan pan){
		Gong mingGong = mingGong(pan);
		return jieXingAnGong(pan, mingGong);
	}
	
	/**
	 * 借星安宫
	 * 本宫无正曜的时候，借对宫星安宫
	 * @param pan
	 * @param gong
	 * @return
	 */
	public static List<Star> jieXingAnGong(MingPan pan, Gong gong){
		List<Star> stars = gong.getZhengYaoList();
		if(stars.isEmpty()){
			int pos = (gong.getGongZhi().ordinal() + 6)%12;
			stars.addAll(pan.getGongList().get(pos).getAllStar());
		}
		return stars;
	}
	
	/**
	 * 三方四正
	 * 获得指定宫的三方四正中的所有星曜
	 * @param pan
	 * @param gong
	 * @return
	 */
	public static List<Star> sanFangSiZheng(MingPan pan, Gong gong){
		List<Star> stars = gong.getZhengYaoList();
		int duigong = (gong.getGongZhi().ordinal() + 6)%12;
		int zuofang = (gong.getGongZhi().ordinal() + 4)%12;
		int youfang = (gong.getGongZhi().ordinal() + 8)%12;
		
		stars.addAll(gong.getAllStar());
		stars.addAll(pan.getGongList().get(duigong).getAllStar());
		stars.addAll(jieXingAnGong(pan, pan.getGongList().get(zuofang)));
		stars.addAll(jieXingAnGong(pan, pan.getGongList().get(youfang)));
		return stars;
	}
	
	/**
	 * 百官朝拱
	 * @param pan
	 * @param gong
	 * @return
	 */
	public static List<Star> baiGuanChaoGong(MingPan pan, Gong gong){
		List<Star> starList = new ArrayList<Star>();
		boolean flag = false;
		for(Star star : gong.getZhengYaoList()){
			if(star.getStarCode() == StarCode.ZIWEI 
				|| star.getStarCode() == StarCode.TAIYANG){
				flag = true;
			}
		}
		
		if(!flag){
			return starList;
		}
		
		List<Star> stars = sanFangSiZheng(pan, gong);
		for(Star star : stars){
			if(star.getStarCode() == StarCode.TIANFU || star.getStarCode() == StarCode.TIANXIANG){
				starList.add(star);
			}
			if(star.getSiHua() == StarCode.HUALU || star.getSiHua() == StarCode.HUAQUAN
				|| star.getSiHua() == StarCode.HUAKE){
				starList.add(star);
			}
			starList.addAll(jianXingXunOu(stars, star));
		}
		return starList;
	}
	
	public static boolean luquankehui(MingPan pan, Gong gong){
		List<Star> stars = sanFangSiZheng(pan, gong);
		int count = 0;
		for(Star star : stars){
			StarCode sc = star.getSiHua();
			if(sc == StarCode.HUALU || sc == StarCode.HUAQUAN || sc == StarCode.HUAKE){
				count++;
			}
		}
		if(count == 3){
			return true;
		}
		return false;
	}
	
	/**
	 * 见星寻偶
	 * @param stars
	 * @param star
	 * @return
	 */
	public static List<Star> jianXingXunOu(List<Star> stars , Star star){
		List<Star> starList = new ArrayList<Star>();
		StarCode target = null;
		switch(star.getStarCode()){
		case ZUOFU:
			target = StarCode.YOUBI;
			break;
		case YOUBI:
			target = StarCode.YOUBI;
			break;
		case WENQU:
			target = StarCode.WENCHANG;
			break;
		case WENCHANG:
			target = StarCode.WENQU;
			break;
		case TIANKUI:
			target = StarCode.TIANYUE;
			break;
		case TIANYUE:
			target = StarCode.TIANKUI;
			break;	
		case LUCUN:
			target = StarCode.TIANMA;
			break;
		case TIANMA:
			target = StarCode.LUCUN;
			break;
		case SANTAI:
			target = StarCode.BAZUO;
			break;
		case BAZUO:
			target = StarCode.SANTAI;
			break;
		case LONGCHI:
			target = StarCode.FENGGE;
			break;
		case FENGGE:
			target = StarCode.LONGCHI;
			break;
		case TAIFU:
			target = StarCode.FENGGAO;
			break;
		case FENGGAO:
			target = StarCode.TAIFU;
			break;
		case ENGUANG:
			target = StarCode.TIANGUI;
			break;	
		case TIANGUI:
			target = StarCode.ENGUANG;
			break;
		default:
			break;
		}

		for(Star s : stars){
			if(s.getStarCode() == target){
				starList.add(star);
				starList.add(s);
			}
		}
		return starList;
	}
}
